package cn.hallele.bbts.core.module.core.encode;

import cn.hallele.bbts.core.common.constants.MsgCodeConst;
import cn.hallele.bbts.core.common.exceptions.CoreException;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;

/**
 * BBTSCoreApp
 *
 * @author anle5
 * @since 2023/11/29 星期三 22:57
 */
@Slf4j
@Service
public class RSAPasswordEncode implements PasswordEncoder {
    private RSA rsa;

    /**
     * RSAPasswordEncode
     */
    public RSAPasswordEncode() {
    }

    /**
     * rsa公私钥
     *
     * @param publicKey  公钥
     * @param privateKey 私钥
     */
    public RSAPasswordEncode(String publicKey, String privateKey) {
        rsa = SecureUtil.rsa(privateKey, publicKey);
    }

    /**
     * Encode the raw password. Generally, a good encoding algorithm applies a SHA-1 or
     * greater hash combined with an 8-byte or greater randomly generated salt.
     *
     * @param rawPassword 原密码
     */
    @Override
    public String encode(CharSequence rawPassword) {
        return rsa.encryptHex(rawPassword.toString().getBytes(StandardCharsets.UTF_8), KeyType.PublicKey);
    }

    /**
     * Verify the encoded password obtained from storage matches the submitted raw
     * password after it too is encoded. Returns true if the passwords match, false if
     * they do not. The stored password itself is never decoded.
     *
     * @param rawPassword     the raw password to encode and match
     * @param encodedPassword the encoded password from storage to compare with
     * @return true if the raw password, after encoding, matches the encoded password from
     * storage
     */
    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {
        if (rawPassword == null) {
            throw new IllegalArgumentException("rawPassword cannot be null");
        }
        if (StringUtils.isBlank(encodedPassword)) {
            log.warn("Empty encoded password");
            return false;
        }
        String clearRawPassword;
        String clearEncodedPassword;
        try {
            clearRawPassword = StrUtil.str(rsa.decrypt(rawPassword.toString(), KeyType.PrivateKey), CharsetUtil.UTF_8);
            clearEncodedPassword = StrUtil.str(rsa.decrypt(encodedPassword, KeyType.PrivateKey), CharsetUtil.UTF_8);
            return clearRawPassword.equals(clearEncodedPassword);
        } catch (Exception e) {
            log.error("加解密异常.", e);
            throw new CoreException(MsgCodeConst.ENCRYPT_OR_DECRYPT_ERROR);
        }

    }
}